package com.tianji.promotion.service.impl;

import com.tianji.promotion.constants.PromotionConstants;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.ExchangeCode;
import com.tianji.promotion.mapper.ExchangeCodeMapper;
import com.tianji.promotion.service.IExchangeCodeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.utils.CodeUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

import static com.tianji.promotion.constants.PromotionConstants.COUPON_RANGE_KEY;

/**
 * <p>
 * 兑换码 服务实现类
 * </p>
 *
 * @author 晚风
 * @since 2023-09-27
 */
@Service
@RequiredArgsConstructor
public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, ExchangeCode> implements IExchangeCodeService {

    private final StringRedisTemplate redisTemplate;

    @Override
    @Async("generateExchangeCodeExecutor")
    public void asyncGenerateExchangeCode(Coupon coupon) {
        Integer totalNum = coupon.getTotalNum();  // 发放优惠券的总数量，也代表需要生成兑换码的总数量
        // 方式一：循环兑换码数量  效率不高
        // 方式二：调用incrby 批量生成兑换码 （只需要操作一次redis）
        // 1. 生成自增id  借助于 redis incr
        Long increment = redisTemplate.opsForValue().increment(PromotionConstants.COUPON_CODE_SERIAL_KEY, totalNum);
        int maxSerialNum = increment.intValue(); // 本地自增id最大值
        int begin = maxSerialNum - totalNum; //  自增id开始值
        // 2. 调用工具类生成兑换码
        List<ExchangeCode> list = new ArrayList<>();
        for (int i = begin; i <= maxSerialNum; i++) {
            String code = CodeUtil.generateCode(i, coupon.getId());// 参数一为自增id  参数二为  优惠券id (内部会计算出0-15之间的一个数字)
            ExchangeCode exchangeCode = new ExchangeCode();
            exchangeCode.setId(i); // 兑换码id
            exchangeCode.setCode(code); // 兑换码
            exchangeCode.setExchangeTargetId(coupon.getId()); // 优惠券id
            exchangeCode.setExpiredTime(coupon.getIssueEndTime()); // 兑换码过期时间
            list.add(exchangeCode);
        }
        // 3. 将兑换码保存到db  exchange_code  批量保存
        this.saveBatch(list);

        // 4. 写入redis 缓存 member:couponId , score 兑换码的最大序列号 （本次生成兑换码）
        redisTemplate.opsForZSet().add(COUPON_RANGE_KEY,coupon.getId().toString(),maxSerialNum);
    }

    @Override
    public boolean updateExchangeCodeMark(long serialNum, boolean flag) {
        String key = PromotionConstants.COUPON_CODE_MAP_KEY;
        //  修改兑换码 的 自增id 的offset对应的值
        Boolean aBoolean = redisTemplate.opsForValue().setBit(key, serialNum, flag);
        return aBoolean != null && aBoolean;
    }
}
